package com.iot.core.manager.auth;


import com.iot.core.data.IdNameDto;
import com.iot.core.data.TreeViewNode;
import com.iot.core.data.entity.HtMenu;
import com.iot.core.data.entity.HtPage;
import com.iot.core.data.entity.HtPageAuth;
import com.iot.core.data.entity.HtUserLogin;
import com.iot.core.data.mapper.*;
import com.iot.core.data.service.IHtRoleMenuService;
import com.iot.core.data.service.IHtUserDeptService;
import com.iot.core.data.service.IHtUserRoleService;
import com.iot.core.enums.AuthType;
import com.iot.core.exception.MyException;
import com.iot.core.manager.htctl.HtCtlActDto;
import com.iot.core.manager.htctl.HtCtlManager;
import com.iot.core.manager.id.HtIdManager;
import com.iot.core.springboot.MyThreadLocal;
import com.iot.core.util.MyJSON;
import com.iot.core.util.MyStringUtil;
import com.iot.core.util.StreamUtil;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.update.UpdateChain;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

import static com.iot.core.data.entity.table.HtActionTableDef.HT_ACTION;
import static com.iot.core.data.entity.table.HtMenuTableDef.HT_MENU;
import static com.iot.core.data.entity.table.HtPageAuthTableDef.HT_PAGE_AUTH;
import static com.iot.core.data.entity.table.HtUserLoginTableDef.HT_USER_LOGIN;
import static com.iot.core.data.entity.table.HtUserTableDef.HT_USER;

@Slf4j
public class AuthManager {
    @Autowired
    HtUserLoginMapper htUserLoginMapper;

    @Autowired
    HtUserMapper htUserMapper;

    @Autowired
    IHtUserDeptService iHtUserDeptService;
    @Autowired
    IHtUserRoleService iHtUserRoleService;

    @Autowired
    IHtRoleMenuService iHtRoleMenuService;

    @Autowired
    HtPageAuthMapper htPageAuthMapper;
    @Autowired
    HtMenuMapper htMenuMapper;
    @Autowired
    HtPageMapper htPageMapper;
    @Autowired
    HtCtlMapper htCtlMapper;
    @Autowired
     HtActionMapper htActionMapper;

    private static   AuthManager instance = null;


    //2.构造方法设为 private
    public AuthManager() {
       instance=this;
    }

    public static AuthManager getInstance() {

        return instance;
    }
    /*获取用户信息*/
    public HtUserLogin getSuByToken(String token )
    {
       var qw=new QueryWrapper();
       qw.where(HT_USER_LOGIN.TOKEN.eq(token));
       var m=htUserLoginMapper.selectOneByQuery(qw);
        if (m!=null)
        {
            m.setHtroles(  MyJSON.parseArray(    m.getHtroleData(), IdNameDto.class)  );
        }
        return m;
    }
        //生成密码
    public String createPwd(String ename,String pwd)
    {
        var s=com.iot.core.util.MD5.get(ename + pwd);
        return s;
    }
    //生成Token
    public String createToken(long lgid)
    {
        var s = HtIdManager.getInstance().nextGuid().toString();
        return s;
    }

    //用户密码检查
    //返回机构
    public List<HtDeptBaseDto> loginCheck(LoginUserPwdDto loginInfo )
    {
        var ckPWD = createPwd(loginInfo.getEname(), loginInfo.getPwd());
        var qw=new  QueryWrapper();
        qw.where(HT_USER.ENAME.eq( loginInfo.getEname()) );

        var muser=htUserMapper.selectOneByQuery(qw);
        if(muser==null)
        {
            throw new MyException("用户不存在");
        }
        if(!muser.getPwd().toUpperCase().equals(ckPWD.toUpperCase()) ) {
            throw new MyException("密码错误");
        }

        var l=iHtUserDeptService.getDepts(muser.getId() );
        return l;
    }


    @Transactional(rollbackFor = Exception.class)
    //登录
    public  String login(LoginDto mm){
        var loginUserPwdDto = new LoginUserPwdDto();
        loginUserPwdDto.setEname(mm.getEname());
        loginUserPwdDto.setPwd(mm.getPwd());

        var ldept = loginCheck(loginUserPwdDto );

        HtDeptBaseDto mdept = null;
        if (ldept.size() == 0)
        {
            throw new MyException("没有机构");
        }
        if (mm.getHtdeptId() > 0)
        {
            ldept = StreamUtil.list(ldept, a->a.getId().equals(mm.getHtdeptId())) ;
        }
        if (mm.getHtdeptId() > 0)
        {
            ldept = StreamUtil.list(ldept,a->a.getHtplatId().equals(mm.getHtplatId())) ;
        }
        if (ldept.size()!=1)
        {
            throw new MyException("请登录机构");
        }
        mdept = ldept.get(0);


        var qwuser=new  QueryWrapper();
        qwuser.where(HT_USER.ENAME.eq( mm.getEname()) );
        var muser=htUserMapper.selectOneByQuery(qwuser);

        var su= MyThreadLocal.get().getSu();
        su.setId(HtIdManager.getInstance().nextLong() );
        su.setToken(  createToken(su.getId() ) );
        su.setName(muser.getName());
        su.setCrtUid(muser.getId() );
        su.setCrtDid(mdept.getId() );
        su.setHtdeptId(mdept.getId());
        su.setHtdeptName(mdept.getName() );
        su.setHtplatId(mdept.getHtplatId());
        su.setOnline(true);
        su.setLoginway(mm.getLoginway());

        su.setCrtDt(new Date());
        su.setEdtDt(new Date());
        su.setLogoutDt(new Date());
        if (mm.getExtra().size()>0 )
        {
            if (mm.getExtra().containsKey("appver"))
            {
                su.setAppver( mm.getExtra().get("appver")  );
            }
            if (mm.getExtra().containsKey("imsi"))
            {
                su.setImsi( mm.getExtra().get("imsi")  );
            }

            su.setExtra( MyJSON.toJSONString(mm.getExtra()) );
        }
        var log = MyThreadLocal.get().getMylog();
        log.setName(muser.getName());
        muser.setCrtUid(muser.getId());
        log.setCrtDid(mdept.getId());
        log.setHtdeptId(mdept.getId());
        log.setHtdeptName(mdept.getName());
        log.setHtplatId(su.getHtplatId());

        var lrole=iHtUserRoleService.getRoles(muser.getId(),mdept.getId() );

        su.setHtroles(lrole);
        su.setHtroleData(MyJSON.toJSONString(lrole));

        UpdateChain.of(HtUserLogin.class)
                .set(HtUserLogin::isOnline, false)
                .set(HtUserLogin::getLogoutDt,new Date() )
                .set(HtUserLogin::getLogoutMemo,String.format("被 %s 踢下线",su.getIp() ) )
                .where(
                        HtUserLogin::isOnline
                ).eq(true)
                .and( HtUserLogin::getCrtUid).eq(su.getCrtUid())
                .and(HtUserLogin::getLoginway).eq(su.getLoginway() )
                .update();


        htUserLoginMapper.insert(su);
        //缓存menu
        //缓存url

        return su.getToken();
    }
    public  List<TreeViewNode> getMenuByHtplatId(long htplat_Id){
         var qwMenu=new  QueryWrapper();
         qwMenu.where(HT_MENU.HTPLAT_ID.eq(htplat_Id));
         var l=htMenuMapper.selectListByQuery(qwMenu);

         List<Long> lpageid=null;
         lpageid=l.stream().map(a->a.getHtpageId()).distinct().collect(Collectors.toList());
         List<HtPageAuth> lpageauth=new ArrayList<>();
         List<HtPage> lpage=new ArrayList<>();
         var r=new ArrayList<TreeViewNode>();
         if(lpageid.size()>0){
             lpage=htPageMapper.selectListByIds(lpageid);
             lpageid=lpage.stream().map(a->a.getId()).collect(Collectors.toList());
             if(lpageid.size()>0){
                 var qwpa=new QueryWrapper();
                 qwpa.where(HT_PAGE_AUTH.HTPAGE_ID.in(  lpageid) );
                 lpageauth=htPageAuthMapper.selectListByQuery(qwpa);
             }
         }
        addChildMenu(r,null,l,lpage,lpageauth);
         return r;
    }
    TreeViewNode createByPage(HtMenu mmenu, HtPage mpage, List<HtPageAuth> lpageauth) throws RuntimeException
    {

        var tnc = new TreeViewNode();
        htMenuMapper.entityToDto(mmenu, tnc);
        tnc.setCode(mpage.getCode());
        tnc.setName(mpage.getName());
        tnc.setImgurl(mpage.getImgurl());


        for(var m : lpageauth)
        {
            var tnc2 = new TreeViewNode();

            tnc2.setLx("权限");
            tnc2.setObj(m.getUrls());
            htPageAuthMapper.entityToDto(m, tnc2);
            tnc.getChildren().add(tnc2);
        }
        return tnc;
    }
    void addChildMenu(List<TreeViewNode> r,TreeViewNode tn, List< HtMenu> l,
                  List< HtPage> lpage,
                  List< HtPageAuth> lpageauth
    )
    {
        var pid=tn==null?0L:tn.getId();
        l.stream().filter(a->a.getPid().equals(pid))
                .sorted(Comparator.comparing(HtMenu::getSortno) )
                .collect(Collectors.toList())
                .forEach(mmenu->{
                    if(mmenu.getHtpageId()>0){
                        var mpage=StreamUtil.get(lpage,a->a.getId().equals(mmenu.getHtpageId()));
                        if(mpage!=null&&!mpage.isDeleted()){
                            var lpageAuth2=StreamUtil.list(lpageauth,a->a.getHtpageId().equals(mpage.getId()), Comparator.comparing(HtPageAuth::getSortno) );
                            var tnc = createByPage(mmenu,mpage, lpageAuth2);
                            if(tn!=null){
                                tn.getChildren().add(tnc);
                            }else {
                                r.add(tnc);
                            }
                            addChildMenu(r,tnc, l, lpage, lpageauth);

                        }
                    }else{
                        var tnc = new TreeViewNode();
                        htMenuMapper.entityToDto(mmenu, tnc);
                        tnc.setObj( mmenu.getHtpageId().toString() );
                        if(tn!=null){
                            tn.getChildren().add(tnc);
                        }else {
                            r.add(tnc);
                        }
                        addChildMenu(r,tnc, l, lpage, lpageauth);
                    }
                });
    }


    public   int createPageByCtl(CreatePageByCtlDto mm)
    {


        var mctl = htCtlMapper.selectOneById(mm.getId());
        var qwaction=new  QueryWrapper();
        qwaction.where(HT_ACTION.CTL_FULL_NAME.eq(mctl.getCtlFullName()));
        qwaction.and(HT_ACTION.AUTH_TYPE.eq( "Auth" ) );
        qwaction.orderBy("id");
        var laction=htActionMapper.selectListByQuery(qwaction);

        var arr = mctl.getCtlFullName().split("\\.");
        var Code = arr[arr.length - 1].replace("Controller", "").toLowerCase();

        var mpage = new  HtPage();
        mpage.setId(mm.isReserveid()?mctl.getId():HtIdManager.getInstance().nextLong());
        mpage.setCode(Code);
        mpage.setMemo(mctl.getMemo());
        mpage.setImgurl("");

        if (mm.isReserveid())
        {
            var mpage2=htPageMapper.selectOneById(mpage.getId());
            if (mpage2!= null)
            {
                return 0;
            }
        }
        htPageMapper.insert(mpage, true );
        if ("1".equals(mm.getMode() ) )//完全权限
        {
            var Urls = "";
            for(var mation : laction)
            {
                Urls += mation.getFullUrl() + ",";
            }
            Urls= MyStringUtil.trimEnd(Urls,",");

            var mauth = new  HtPageAuth();
            mauth.setId(mm.isReserveid()?(mctl.getId()+1):HtIdManager.getInstance().nextLong());
            mauth.setHtpageId(  mpage.getId());
            mauth.setCode("*");
            mauth.setUrls(Urls);
            mauth.setName("完全权限");
            mauth.setMemo("");
            mauth.setSortno(10L);
            htPageAuthMapper.insert(mauth,true);

        }
        else
        {
            for (var mation: laction)
            {
                var mauth = new  HtPageAuth();
                mauth.setId(mm.isReserveid()?mation.getId():HtIdManager.getInstance().nextLong());
                mauth.setHtpageId(mpage.getId());
                mauth.setCode(mation.getFullUrl());
                mauth.setUrls(mation.getFullUrl());
                mauth.setName(mation.getName());
                mauth.setMemo("");
                mauth.setSortno( mation.getId()-mctl.getId() );
                htPageAuthMapper.insert(mauth,true);

            }

        }

        return 1;

    }

    public boolean hasUrl(HtUserLogin su,String url){
        if(su.getCrtUid().equals(1000L)){
            return true;
        }
        url = url.toLowerCase();
        var mact = HtCtlManager.getInstance().getAction(url);
        if (mact == null)
        {
            return true;
        }
        return true;// hasUrl(su,mact);
    }

    public boolean hasUrl(HtUserLogin su, HtCtlActDto mact)
    {
        if(su.getCrtUid().equals(1000L)){
            return true;
        }
        if (mact.getAuthType().equals(AuthType.None) )
        {
            return true;
        }

        if (mact.getAuthType().equals(AuthType.Login) )
        {
            return su.getCrtUid()>0L;
        }

        var rids = su.getHtroles().stream().map( a -> a.getId()).collect(Collectors.toList()) ;
        var lurls=iHtRoleMenuService.getRolesUrls(rids);
        String finalUrl = mact.getFullUrl();
        var murl= StreamUtil.get(lurls,a->a.equals(finalUrl));
        if (murl!=null)
        {
            return true;
        }
        var l2 = new ArrayList<String>();
        AtomicBoolean bfound= new AtomicBoolean(false);
        lurls.forEach(murl2->{
            if(murl2.indexOf(",")>0){
                var arr=murl2.split(",");
                for(var i=0;i<arr.length;i++){
                    if(arr[i].trim().equals(finalUrl)){
                        bfound.set(true);
                        return ;
                    }
                    l2.add( arr[i].trim() );
                }

            }
        });
        if(bfound.get()){
            return true;
        }

        lurls.addAll(l2);

        var ib = mact.getFullUrl().lastIndexOf("/");
        var url= mact.getFullUrl().substring(0, ib)+"/*";
        var finalUrl2=url;
        murl= StreamUtil.get(lurls,a->a.equals(finalUrl2));
        if (murl!=null)
        {
            return true;
        }
        return false;
    }



}
